home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dviselect / split.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-16  |  4.4 KB  |  220 lines

  1. /*
  2.  * Copyright (c) 1987 University of Maryland Department of Computer Science.
  3.  * All rights reserved.  Permission to copy for any purpose is hereby granted
  4.  * so long as this copyright notice remains intact.
  5.  */
  6.  
  7. #ifndef lint
  8. static char rcsid[] = "$Header: split.c,v 1.1 88/02/11 17:08:56 jim Exp $";
  9. #endif
  10.  
  11. #include <ctype.h>
  12.  
  13. /*
  14.  * Split a line into an array of words.  This is destructive of
  15.  * the original line; the word pointers point to places within
  16.  * that line.
  17.  *
  18.  * Return the number of words made, or -1 for overflow.
  19.  */
  20.  
  21. /*
  22.  * The lexical states are much like `sh's, except that we also do
  23.  * C-style backslash-escapes.
  24.  */
  25. enum lexstate {
  26.     S_BLANK,        /* outside a word */
  27.     S_WORD,            /* inside a word, no quoting */
  28.     S_SQUOTE,        /* inside a single quote */
  29.     S_DQUOTE,        /* inside a double quote */
  30.     S_BKSL0,        /* last char was \ */
  31.     S_BKSL1,        /* last chars were \, [0-7] */
  32.     S_BKSL2            /* last chars were \, [0-7][0-7] */
  33. };
  34.  
  35. int
  36. split(s, w, nw)
  37.     register char *s, **w;
  38.     int nw;
  39. {
  40.     register int c;
  41.     register char *canon = s;
  42.     register int wleft = nw;
  43.     enum lexstate state, prebkstate;
  44.  
  45.     /*
  46.      * Start out in the `blank' state (outside a word).  Handle
  47.      * quotes and things.  Backslashes are handled by saving the
  48.      * `pre-backslash' state, doing the backslash, and restoring
  49.      * that state at the end of the backslash sequence.
  50.      */
  51.     state = S_BLANK;
  52.     while ((c = *s++) != 0) {
  53. reswitch:
  54.         switch (state) {
  55.  
  56.         /*
  57.          * Blanks: spaces stay in blank state; anything
  58.          * else starts a word.  However, quotes may put
  59.          * us into quote states, rather than word states.
  60.          */
  61.         case S_BLANK:
  62.             if (isspace(c))
  63.                 continue;
  64.             if (--wleft < 0)
  65.                 return (-1);
  66.             *w++ = canon;
  67.             state = S_WORD;
  68.             /* FALLTHROUGH */
  69.  
  70.         /*
  71.          * In a word.  Spaces take us out (and end the
  72.          * current word).  Quotes, however, put us into
  73.          * quote states.
  74.          */
  75.         case S_WORD:
  76.             if (isspace(c)) {
  77.                 *canon++ = 0;
  78.                 state = S_BLANK;
  79.                 break;
  80.             }
  81.             if (c == '\'') {
  82.                 state = S_SQUOTE;
  83.                 break;
  84.             }
  85.             if (c == '"') {
  86.                 state = S_DQUOTE;
  87.                 break;
  88.             }
  89.             if (c == '\\') {
  90.                 prebkstate = S_WORD;
  91.                 state = S_BKSL0;
  92.                 break;
  93.             }
  94.             *canon++ = c;
  95.             break;
  96.  
  97.         /*
  98.          * Inside a single quote, the only special character
  99.          * is another single quote.  This matches the Bourne
  100.          * shell quoting convention exactly.
  101.          */
  102.         case S_SQUOTE:
  103.             if (c == '\'')
  104.                 state = S_WORD;
  105.             else
  106.                 *canon++ = c;
  107.             break;
  108.  
  109.         /*
  110.          * Inside a double quote, double quotes get us out,
  111.          * but backslashes must be interpreted.
  112.          */
  113.         case S_DQUOTE:
  114.             if (c == '\\') {
  115.                 prebkstate = S_DQUOTE;
  116.                 state = S_BKSL0;
  117.             } else if (c == '"')
  118.                 state = S_WORD;
  119.             else
  120.                 *canon++ = c;
  121.             break;
  122.  
  123.         /*
  124.          * If we are handling a backslash, we will either
  125.          * restore the state, or go to BKSL1 state.  In
  126.          * the latter case, do not advance the canonicalisation
  127.          * pointer, since we might have more octal digits
  128.          * to insert.
  129.          */
  130.         case S_BKSL0:
  131.             state = prebkstate;    /* probably */
  132.             switch (c) {
  133.  
  134.             case 'b':
  135.                 *canon++ = '\b';
  136.                 break;
  137.  
  138.             case 'f':
  139.                 *canon++ = '\f';
  140.                 break;
  141.  
  142.             case 'n':
  143.                 *canon++ = '\n';
  144.                 break;
  145.  
  146.             case 'r':
  147.                 *canon++ = '\r';
  148.                 break;
  149.  
  150.             case 't':
  151.                 *canon++ = '\t';
  152.                 break;
  153.  
  154.             case '0': case '1': case '2': case '3':
  155.             case '4': case '5': case '6': case '7':
  156.                 *canon = c - '0';
  157.                 state = S_BKSL1;
  158.                 break;
  159.  
  160.             default:
  161.                 *canon++ = c;
  162.                 break;
  163.             }
  164.             break;
  165.  
  166.  
  167.         /*
  168.          * In BKSL1, we have seen backslash and one octal
  169.          * digit.  There may be more (in which case just
  170.          * count them on in), or there might be something
  171.          * that requires we restore the state and try again.
  172.          */
  173.         case S_BKSL1:
  174.             switch (c) {
  175.  
  176.             case '0': case '1': case '2': case '3':
  177.             case '4': case '5': case '6': case '7':
  178.                 *canon <<= 3;
  179.                 *canon |= c - '0';
  180.                 state = S_BKSL2;
  181.                 break;
  182.  
  183.             default:
  184.                 canon++;
  185.                 state = prebkstate;
  186.                 goto reswitch;
  187.             }
  188.             break;
  189.  
  190.         /*
  191.          * BKSL2 is like BKSL1, except that it cannot
  192.          * help but restore the original state, since
  193.          * there are no four-character octal sequences.
  194.          */
  195.         case S_BKSL2:
  196.             state = prebkstate;    /* assuredly */
  197.             switch (c) {
  198.  
  199.             case '0': case '1': case '2': case '3':
  200.             case '4': case '5': case '6': case '7':
  201.                 *canon <<= 3;
  202.                 *canon++ |= c - '0';
  203.                 break;
  204.  
  205.             default:
  206.                 canon++;
  207.                 goto reswitch;
  208.             }
  209.             break;
  210.         }
  211.     }
  212. #ifdef notdef
  213.     if (state != S_WORD && state != S_BLANK)
  214.         error(0, 0, "warning: unclosed quote");
  215. #endif
  216.     if (state != S_BLANK)
  217.         *canon = 0;
  218.     return (nw - wleft);
  219. }
  220.